#pragma once

#include<iostream>
#include<vector>
#include<unistd.h>
#include<sys/select.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

#include"Log.hpp"

class Select
{
    const int deault_listen_socket_num=5;
public:
    Select(int port)
    {
        //创建监听套接字
        _listenSocket=socket(AF_INET,SOCK_STREAM,0);
        if(_listenSocket<0)
        {
            Log(FATAL,"create listening socket error\n");
            return;
        }

        //设置地址复用
        int opt=1;
        if(setsockopt(_listenSocket,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))<0)
        {
            Log(ERROR,"set address reuse error\n");
        }

        //绑定端口号
        struct sockaddr_in saddr;
        bzero(&saddr,sizeof(saddr));
        saddr.sin_family=AF_INET;
        saddr.sin_port=port;
        saddr.sin_addr.s_addr=INADDR_ANY;
        
        if(bind(_listenSocket,(struct sockaddr*)(&saddr),sizeof(saddr))<0)
        {
            Log(FATAL,"bind error\n");
        }

        //开启监听
        if(listen(_listenSocket,deault_listen_socket_num)<0)
        {
            Log(FATAL,"listen error\n");
        }
        
        int length=sizeof(fd_set)*8;
        _arrOffd.resize(length,-1);
        _arrOffd[0]=_listenSocket;
    }

    void GetNewClientLink()
    {
        struct sockaddr_in caddr;
        unsigned int len=sizeof(caddr);
        int sockfd=accept(_listenSocket,(struct sockaddr*)(&caddr),&len);
        if(sockfd<0)
        {
            Log(ERROR,"accept error\n");
            return;
        }

        //将新连接的文件描述符放到数组_arrOffd中
        int i=0;
        for(i=0;i<_arrOffd.size();++i)
        {
            if(-1==_arrOffd[i])
            {
                _arrOffd[i]=sockfd;
                return;
            }
        }

        Log(ERROR,"the number of function select can moninor is full\n");
    }

    void NormalIO(int i)
    {
        char buf[1024];
        int n=read(_arrOffd[i],buf,sizeof(buf));
        if(n>0)
        {
            printf("%d %d %d\n",getpid(),i,n);
            buf[n]=0;
            printf("read: %s\n",buf);
        }
        else if(0==n)
        {
            _arrOffd[i]=-1;
            Log(DEBUG,"the client close link\n");
        }
        else
        {
            Log(ERROR,"read fd %d error\n",_arrOffd[i]);
        }
    }

    void HandleEvent(fd_set fs)
    {
        int i=0;
        for(i=0;i<_arrOffd.size();++i)
        {
            if(FD_ISSET(_arrOffd[i],&fs))
            {
                if(_arrOffd[i]==_listenSocket)
                {
                    Log(DEBUG,"get new link\n");
                    GetNewClientLink();
                }
                else
                {
                    Log(DEBUG,"normal data io\n");
                    NormalIO(i);
                }
            }
        }
    }
    
    void Start()
    {
        while(true)
        {
            fd_set rfs;
            FD_ZERO(&rfs);
            int max_socket=-1;
            for(auto e:_arrOffd)
            {
                if(-1!=e)
                {
                    FD_SET(e,&rfs);
                    if(max_socket<e)
                    {
                        max_socket=e;
                    }
                }
            }
            //在这个使用事例中我们只关心读
            int n=select(max_socket+1,&rfs,nullptr,nullptr,nullptr);
            if(n>0)
            {
                Log(DEBUG,"event happened\n");
                HandleEvent(rfs);
            }
            else if(0==n)
            {
                Log(DEBUG,"time out\n");
            }
            else
            {
                Log(ERROR,"select error\n");
            }
        }
    }

    ~Select()
    {
        if(_listenSocket>0)
        {
            close(_listenSocket);
        }
    }

private:
    int _port;
    int _listenSocket;
    std::vector<int> _arrOffd;
};